package models

import (
	"fmt"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
	"math"
	"regexp"
	"strconv"
	"strings"
)

const pageSize = 10

var (
	db orm.Ormer
)

type MovieInfo struct {
	Id                 int64
	MovieId            int64
	MovieName          string
	MoviePic           string
	MovieDirector      string
	MovieWriter        string
	MovieCountry       string
	MovieLanguage      string
	MovieMainCharacter string
	MovieType          string
	MovieOnTime        string
	MovieSpan          string
	MovieGrade         string
	MovieSynopsis      string
	Remark             string
}

type Page struct {
	PageNo int
	PageSize int
	Total int
	PageCount int
	Data interface{}
}

func init() {
	orm.Debug = true
	_ = orm.RegisterDataBase("default", "mysql", "reptile:D4ertTrzAkwKWTKE@tcp(127.0.0.1:3306)/reptile?charset=utf8")
	orm.RegisterModel(new(MovieInfo))
	db = orm.NewOrm()
}

func AddMovie(movieInfo *MovieInfo) (int64, error) {
	id, err := db.Insert(movieInfo)
	return id, err
}

func AddMovieByMovieId(movieInfo *MovieInfo) {
	qb, _ := orm.NewQueryBuilder("mysql")
	count := 0
	_ = db.Raw(qb.Select("COUNT(id)").From("movie_info").Where("movie_id = ?").String(), movieInfo.MovieId).QueryRow(&count)
	if count == 0 {
		_, _ = AddMovie(movieInfo)
	}
}

func getMovieInfo(html string, regexpStr string, many bool) string {
	if html == "" {
		return ""
	}
	result := ""
	reg := regexp.MustCompile(regexpStr)
	results := reg.FindAllStringSubmatch(html, -1)
	if results == nil {
		return ""
	}
	if len(results) > 1 {
		for _, v := range results {
			result += v[1] + "/"
		}
		result = result[:len(result)-1]
	}else if strings.Contains(results[0][0], " / ") && many{
		regs := strings.Split(results[0][0], " / ")
		for _, v := range regs {
			res := reg.FindAllStringSubmatch(v, -1)
			if res != nil && len(res[0]) > 1{
				result += res[0][1] + "/"
			}
		}
		result = result[:len(result)-1]
	}else {
		result += results[0][1]
	}
	return result
}

func GetMovieId(html string) int64 {
	res := getMovieInfo(html, `<span\s*class="rec"\s*id="电影-(.*?)">`, false)
	movieId, err := strconv.ParseInt(res, 10, 64)
	if err != nil {
		_ = fmt.Errorf("%v", err)
		movieId = -1
	}
	return movieId
}

func GetMovieName(html string) string {
	name := getMovieInfo(html, `<span\s*property="v:itemreviewed">(.*)</span>`, false)
	fmt.Println("电影名：", name)
	return name
}

func GetMoviePic(html string) string {
	return getMovieInfo(html, `<div\s*id="mainpic"[\s\S]*<img\s*src="(.*?)"\s*title=".*"\s*alt=".*"\s*rel="v:image".*>[\s\n]*</a>[\s\n]*</div>`, false)
}

func GetMovieDirector(html string) string {
	return getMovieInfo(html, `<a.*rel="v:directedBy">(.*)</a>`, true)
}

func GetMovieWrite(html string) string {
	if html == "" {
		return ""
	}
	reg := regexp.MustCompile(`<span ><span class='pl'>编剧</span>: <span class='attrs'>(.*?)</span></span><br/>`)
	results := reg.FindAllStringSubmatch(html, -1)
	if results == nil {
		return ""
	}
	return getMovieInfo(results[0][1], `<a.*>(.*?)</a>`, true)
}

func GetMovieCharacters(html string) string {
	return getMovieInfo(html, `<a.*rel="v:starring">(.*?)</a>`, true)
}

func GetMovieType(html string) string {
	return getMovieInfo(html, `<span\s*property="v:genre">(.*?)</span>`, true)
}

func GetMovieCountry(html string) string {
	if html == "" {
		return ""
	}
	result := ""
	reg := regexp.MustCompile(`<span class="pl">制片国家/地区:</span>(.*?)<br/>`)
	results := reg.FindAllStringSubmatch(html, -1)
	if results == nil {
		return ""
	}
	var languages = strings.Split(results[0][1], " / ")
	for _, v := range languages {
		result += strings.TrimSpace(v) + "/"
	}
	result = result[:len(result)-1]
	return result
}

func GetMovieLanguage(html string) string {
	if html == "" {
		return ""
	}
	result := ""
	reg := regexp.MustCompile(`<span class="pl">语言:</span>(.*?)<br/>`)
	results := reg.FindAllStringSubmatch(html, -1)
	if results == nil {
		return ""
	}
	var languages = strings.Split(results[0][1], " / ")
	if languages == nil {
		return ""
	}
	for _, v := range languages {
		result += strings.TrimSpace(v) + "/"
	}
	result = result[:len(result)-1]
	return result
}

func GetMovieOnTime(html string) string {
	return getMovieInfo(html, `<span\s*property="v:initialReleaseDate".*>(.*?)</span>`, true)
}

func GetMovieSpan(html string) string {
	return getMovieInfo(html, `<span\s*property="v:runtime".*>(.*?)</span>`, true)
}

func GetMovieGrade(html string) string {
	return getMovieInfo(html, `<strong.*property="v:average">(.*?)</strong>`, false)
}

func trimHtml(src string) string {
	//将HTML标签全转换成小写
	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
	src = re.ReplaceAllStringFunc(src, strings.ToLower)
	//去除STYLE
	re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
	src = re.ReplaceAllString(src, "")
	//去除SCRIPT
	re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
	src = re.ReplaceAllString(src, "")
	//去除所有尖括号内的HTML代码，并换成换行符
	re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
	src = re.ReplaceAllString(src, "\n")
	//去除连续的换行符
	re, _ = regexp.Compile("\\s{2,}")
	src = re.ReplaceAllString(src, "\n")
	return strings.TrimSpace(src)
}

func GetMovieSynopsis(html string) string {
	reg := regexp.MustCompile(`<div\s*class="indent"\s*id="link-report">[\s\S]*<span\s*property="v:summary".*>\s*([\S\s]*)\s*</span>[\s\n]*<span\s*class="pl">`)
	results := reg.FindAllStringSubmatch(html, -1)
	if results == nil {
		reg = regexp.MustCompile(`<div\s*class="indent"\s*id="link-report">[\s\S]*<span\s*property="v:summary".*>\s*([\S ]*)\s*</span>[\s\n]*</div>`)
		results = reg.FindAllStringSubmatch(html, -1)
	}
	if results == nil {
		reg = regexp.MustCompile(`<div\s*class="indent"\s*id="link-report">[\s\S]*<span\s*property="v:summary".*>\s*([\S\s]*)\s*</span>[\s\S]*<div\s*class="report"`)
		results = reg.FindAllStringSubmatch(html, -1)
	}
	if results == nil {
		reg = regexp.MustCompile(`<div\s*class="indent"\s*id="link-report">[\s\S]*<span\s*property="v:summary".*>\s*([\S\s]*)\s*</span>[\s\S]*</div>[\s\S]*</div>[\s\S]*<div\s*id="dale_movie_subject_banner_after_intro">`)
		results = reg.FindAllStringSubmatch(html, -1)
	}
	if results == nil {
		return ""
	}
	return strings.ReplaceAll(trimHtml(strings.ReplaceAll(results[0][1], "(展开全部)", "")), " ", "")
}

func GetMovieUrls(html string) []string {
	reg := regexp.MustCompile(`<a.*?href="(https://movie.douban.com/subject/.*?/\?from=subject-page)"`)
	result := reg.FindAllStringSubmatch(html, -1)
	var movieSets []string
	if result == nil {
		return movieSets
	}
	for _, v := range result {
		movieSets =	 append(movieSets, v[1])
	}
	return movieSets
}

func MovieList(pageNo int, MovieName string, order string, MovieType string, MovieCountry string) Page {
	if order == "" {
		order = "id"
	}
	total, err := db.QueryTable("movie_info").Filter("movie_name__contains", MovieName).Count()
	if err != nil {
		fmt.Println("ERROR : ", err)
	}
	var movieInfo []MovieInfo
	page := Page{PageNo: pageNo, PageSize: pageSize, Total: int(total), PageCount: int(math.Ceil(float64(float64(total) / pageSize + .4)))}
	_, err = db.QueryTable("movie_info").Filter("movie_name__contains", MovieName).Filter("movie_type__contains", MovieType).Filter("movie_country__contains", MovieCountry).OrderBy("-" + order).Limit(page.PageSize, (page.PageNo - 1) * page.PageSize).All(&movieInfo)
	if err != nil {
		fmt.Println("ERROR : ", err)
	}
	page.Data = movieInfo
	return page
}

func MovieInfoView(id int64) MovieInfo {
	movieInfo := MovieInfo{Id: id}
	err := db.Read(&movieInfo)
	if err != nil {
		fmt.Println("ERROR : ", err)
	}
	return movieInfo
}

func MovieInfoCountry() map[string]string {
	var country []string
	_, err := db.Raw("SELECT movie_country FROM movie_info GROUP BY movie_country").QueryRows(&country)
	if err != nil {
		fmt.Println("ERROR : ", err)
	}
	return arraySplitMap(&country)
}

func MovieInfoType() map[string]string {
	var types []string
	_, err := db.Raw("SELECT movie_type FROM movie_info GROUP BY movie_country").QueryRows(&types)
	if err != nil {
		fmt.Println("ERROR : ", err)
	}

	return arraySplitMap(&types)
}

func arraySplitMap(array *[]string) map[string]string {
	set := make(map[string]string)
	for _, v := range *array {
		if strings.Contains(v, "/") {
			for _, vv := range strings.Split(v, "/") {
				set[vv] = vv
			}
		}else {
			if v != "" {
				set[v] = v
			}
		}
	}
	return set
}